package sk.ygor.raynor.rebind.serializerfactory


import com.google.gwt.core.ext.{GeneratorContext, TreeLogger, Generator}
import com.google.gwt.core.ext.typeinfo.JParameterizedType
import sk.ygor.raynor.rebind.serializable.JSONSerializableGenerator
import com.google.gwt.user.rebind.{SourceWriter, ClassSourceFileComposerFactory}
import sk.ygor.raynor.rebind.common.ScalaGeneratorWorker
import sk.ygor.raynor.client.json.{JSONSerializerFactory, JSONSerializer, JSONSerializationException}
import sk.ygor.xtemplate.ScalaXTemplate

class JSONSerializerFactoryGenerator extends Generator {
  def generate(logger: TreeLogger, context: GeneratorContext, typeName: String) =
    new Worker(logger, context, typeName).generate
}

private class Worker(logger: TreeLogger, context: GeneratorContext, inputTypeName: String)
        extends ScalaGeneratorWorker(logger, context, inputTypeName) {
  def generateHeader(composer: ClassSourceFileComposerFactory) {
    composer.addImplementedInterface(inputTypeName)
    composer.addImplementedInterface(classOf[JSONSerializerFactory.Configuration])
    composer.addImports(
      classOf[JSONSerializer[_]],
      classOf[JSONSerializer.Configuration],
      classOf[JSONSerializer.Transformer]
      )
  }

  private class Template extends ScalaXTemplate() {

    val serializerType = parameter[String]
    val serializerInstanceName = parameter[String]
    val serializableType = parameter[String]
    val methodName = parameter[String]

    val configureSerializer = """
          ((JSONSerializer.Configuration)""" ~ serializerInstanceName ~ """).setTransformer(transformer);
    """

    val defineSerializer = """
        private """ ~ serializerType ~ " " ~  serializerInstanceName ~ " = new " ~ serializerType ~ """();

        public JSONSerializer<""" ~ serializableType ~ "> " ~ methodName ~ """() {
          return """ ~ serializerInstanceName ~""";
        }
    """

    val rootBlock = """
        public void setTransformer(JSONSerializer.Transformer transformer) {
          """ ~ configureSerializer ~ """
        }
    """ ~ defineSerializer
  }


  def generateBody(sourceWriter: SourceWriter) {
    val xtpl = new Template
    val serializableGenerator = new JSONSerializableGenerator()
    for ((method, index) <- inputClassType.getMethods.zipWithIndex) {
      if (!method.getParameters.isEmpty) {
        throw new JSONSerializationException("Must have no parameters")
      }
      if (method.getReturnType.getQualifiedSourceName != classOf[JSONSerializer[_]].getName()) {
        throw new JSONSerializationException("Must return JSONSerializer")
      }
      method.getReturnType.maybeParameterized match {
        case Some(parametrizedSerializer) => {
          xtpl.serializableType.value = parametrizedSerializer.getTypeArgs()(0).getParameterizedQualifiedSourceName()
          xtpl.serializerType.value =  serializableGenerator.generate(logger, context, parametrizedSerializer.getTypeArgs()(0))
          xtpl.serializerInstanceName.value = "serializer" + index
          xtpl.methodName.value = method.getName
          xtpl.configureSerializer.parse
          xtpl.defineSerializer.parse
        }
        case None => throw new JSONSerializationException("Must return parametrized JSONSerializer")
      }
    }
    xtpl.rootBlock.parse
    sourceWriter print xtpl.rootBlock.getText

  }


}
